/* PDCurses */

#include <curspriv.h>

/*man-start**************************************************************

scr_dump
--------

### Synopsis

    int putwin(WINDOW *win, FILE *filep);
    WINDOW *getwin(FILE *filep);
    int scr_dump(const char *filename);
    int scr_init(const char *filename);
    int scr_restore(const char *filename);
    int scr_set(const char *filename);

### Description

   getwin() reads window-related data previously stored in a file by
   putwin(). It then creates and initialises a new window using that
   data.

   putwin() writes all data associated with a window into a file, using
   an unspecified format. This information can be retrieved later using
   getwin().

   scr_dump() writes the current contents of the virtual screen to the
   file named by filename in an unspecified format.

   scr_restore() function sets the virtual screen to the contents of the
   file named by filename, which must have been written using
   scr_dump(). The next refresh operation restores the screen to the way
   it looked in the dump file.

   In PDCurses, scr_init() does nothing, and scr_set() is a synonym for
   scr_restore(). Also, scr_dump() and scr_restore() save and load from
   curscr. This differs from some other implementations, where
   scr_init() works with curscr, and scr_restore() works with newscr;
   but the effect should be the same. (PDCurses has no newscr.)

### Return Value

   On successful completion, getwin() returns a pointer to the window it
   created. Otherwise, it returns a null pointer. Other functions return
   OK or ERR.

### Portability
                             X/Open  ncurses  NetBSD
    putwin                      Y       Y       Y
    getwin                      Y       Y       Y
    scr_dump                    Y       Y       -
    scr_init                    Y       Y       -
    scr_restore                 Y       Y       -
    scr_set                     Y       Y       -

**man-end****************************************************************/

#include <stdlib.h>
#include <string.h>

#define DUMPVER 1   /* Should be updated whenever the WINDOW struct is
                       changed */

int putwin( WINDOW* win, FILE* filep )
{
	static const char* marker = "PDC";
	static const unsigned char version = DUMPVER;

	PDC_LOG( ( "putwin() - called\n" ) );

	/* write the marker and the WINDOW struct */

	if( filep && fwrite( marker, strlen( marker ), 1, filep )
			&& fwrite( &version, 1, 1, filep )
			&& fwrite( win, sizeof( WINDOW ), 1, filep ) )
	{
		int i;

		/* write each line */

		for( i = 0; i < win->_maxy && win->_y[i]; i++ )
			if( !fwrite( win->_y[i], win->_maxx * sizeof( chtype ), 1, filep ) )
			{
				return ERR;
			}

		return OK;
	}

	return ERR;
}

WINDOW* getwin( FILE* filep )
{
	WINDOW* win;
	char marker[4];
	int i, nlines, ncols;

	PDC_LOG( ( "getwin() - called\n" ) );

	win = malloc( sizeof( WINDOW ) );
	if( !win )
	{
		return ( WINDOW* )NULL;
	}

	/* check for the marker, and load the WINDOW struct */

	if( !filep || !fread( marker, 4, 1, filep ) || strncmp( marker, "PDC", 3 )
			|| marker[3] != DUMPVER || !fread( win, sizeof( WINDOW ), 1, filep ) )
	{
		free( win );
		return ( WINDOW* )NULL;
	}

	nlines = win->_maxy;
	ncols = win->_maxx;

	/* allocate the line pointer array */

	win->_y = malloc( nlines * sizeof( chtype* ) );
	if( !win->_y )
	{
		free( win );
		return ( WINDOW* )NULL;
	}

	/* allocate the minchng and maxchng arrays */

	win->_firstch = malloc( nlines * sizeof( int ) );
	if( !win->_firstch )
	{
		free( win->_y );
		free( win );
		return ( WINDOW* )NULL;
	}

	win->_lastch = malloc( nlines * sizeof( int ) );
	if( !win->_lastch )
	{
		free( win->_firstch );
		free( win->_y );
		free( win );
		return ( WINDOW* )NULL;
	}

	/* allocate the lines */

	win = PDC_makelines( win );
	if( !win )
	{
		return ( WINDOW* )NULL;
	}

	/* read them */

	for( i = 0; i < nlines; i++ )
	{
		if( !fread( win->_y[i], ncols * sizeof( chtype ), 1, filep ) )
		{
			delwin( win );
			return ( WINDOW* )NULL;
		}
	}

	touchwin( win );

	return win;
}

int scr_dump( const char* filename )
{
	FILE* filep;

	PDC_LOG( ( "scr_dump() - called: filename %s\n", filename ) );

	if( filename && ( filep = fopen( filename, "wb" ) ) != NULL )
	{
		int result = putwin( curscr, filep );
		fclose( filep );
		return result;
	}

	return ERR;
}

int scr_init( const char* filename )
{
	PDC_LOG( ( "scr_init() - called: filename %s\n", filename ) );

	return OK;
}

int scr_restore( const char* filename )
{
	FILE* filep;

	PDC_LOG( ( "scr_restore() - called: filename %s\n", filename ) );

	if( filename && ( filep = fopen( filename, "rb" ) ) != NULL )
	{
		WINDOW* replacement = getwin( filep );
		fclose( filep );

		if( replacement )
		{
			int result = overwrite( replacement, curscr );
			delwin( replacement );
			return result;
		}
	}

	return ERR;
}

int scr_set( const char* filename )
{
	PDC_LOG( ( "scr_set() - called: filename %s\n", filename ) );

	return scr_restore( filename );
}
